package org.summerframework.web.serializer.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.io.ByteArrayOutputStream;
import java.util.List;

/**
 * redis 值序高性能列化器，
 *
 * @param <T>
 * @author hanxi
 */
public class KryoRedisSerializer<T> implements RedisSerializer<T> {

    @SuppressWarnings("unused")
    private static final String CHAR_SET = "UTF-8";
    private PooledKryoFactory serializer = new PooledKryoFactory();

    public KryoRedisSerializer() {
    }

    public KryoRedisSerializer(List<Class<?>> classes) {
        final Kryo kryo = serializer.getKryo();

        try {
            for (Class aClass : classes) {
                kryo.register(aClass);
            }
        } finally {
            serializer.returnKryo(kryo);
        }
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        Kryo kryo = serializer.getKryo();

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Output output = new Output(outputStream)) {
            kryo.writeClassAndObject(output, t);
            output.flush();
            return outputStream.toByteArray();
        } catch (Exception ex) {
            throw new SerializationException(ex.getMessage(), ex);
        } finally {
            serializer.returnKryo(kryo);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        Kryo kryo = serializer.getKryo();

        try (Input input = new Input(bytes)) {
            return (T) kryo.readClassAndObject(input);
        } catch (Exception ex) {
            throw new SerializationException(ex.getMessage(), ex);
        } finally {
            serializer.returnKryo(kryo);
        }
    }
}
